(PYTHON) Day - 6 Strings(2)

Reference

  • 문제 출처 - HackerRank
  • 파이썬 연습 - Practice - Python

개인적인 생각과 상상으로 작성한 내용들이 포함되어 있습니다
문제를 풀고 Discussion Tab을 참고하며 코드 스타일을 개선하려고 노력하고자 합니다



HackerRank

HackerRank의 Python 연습문제들은 아래와 같은 카테고리로 분류 된다:

Subdomain

  • Introduction
  • Basic Data Types
  • Strings
  • Sets
  • Math
  • Itertools
  • Collections
  • Date and Time
  • Errors and Exceptions
  • Classes
  • Built-Ins
  • Python Functionals
  • Regex and Parsing
  • XML
  • Closures and Decorators
  • Numpy
  • Debugging


Strings

기본 개념

Mutations

list형은 mutable하지만, tuple형은 immutable하다
immutable한 string 변수가 있을 때, 이를 수정하려면 어떻게 해야할까?
예제 : 5번째 위치의 ‘a’ 문자를 ‘k’로 바꿔라

abracadabra
5 k

abrackdabra

5가지 방법으로 문제를 해결해보고 각각의 시간을 측정해보았다
결과를 보면 ''.join() 함수만 사용한 방법이(아래 코드의 4번째 slice_join_2) 가장 수행속도가 빠르다

당연하지만 되도록이면 list(), format() 함수를 사용하거나, 반복문(list comprehension 안에 반복문을 사용)을 사용하지 않는 것이 5~10배 정도 수행시간을 단축시킬 수 있다

import time

def string_to_list(string, position, character):
string_li = list(string)
string_li[position] = character
string = ''.join(string_li)
return string

def string_format(string, position, character):
return ("{}{}{}".format(string[:position], character, string[position + 1:]))

def slice_join_1(string, position, character):
return string[:position] + character + string[position+1:]

def slice_join_2(string, position, character):
return character.join([string[:position], string[position+1:]])

def comprehension_1(string, position, character):
return ''.join([character if i == position else string[i] for i in range(len(string))])

def comprehension_2(string, position, character):
return ''.join([c if p != position else character for p, c in enumerate(string)])

if **name** == '**main**':
s = input()
i, c = input().split()
p = int(i)

start_1 = time.time()
s_1 = string_to_list(s, p, c)
end_1 = time.time()

start_2 = time.time()
s_2 = string_format(s, p, c)
end_2 = time.time()

start_3 = time.time()
s_3 = slice_join_1(s, p, c)
end_3 = time.time()

start_4 = time.time()
s_4 = slice_join_1(s, p, c)
end_4 = time.time()

start_5 = time.time()
s_5 = comprehension_1(s, p, c)
end_5 = time.time()

start_6 = time.time()
s_6 = comprehension_2(s, p, c)
end_6 = time.time()

print(s_1, s_1 == (s_2 and s_3 and s_4 and s_5 and s_6))

print('string_to_list: '.ljust(20), round((end_1 - start_1) * 100, 8))
print('string_format: '.ljust(20), round((end_2 - start_2) * 100, 8))
print('slice_join_1: '.ljust(20), round((end_3 - start_3) * 100, 8))
print('slice_join_2: '.ljust(20), round((end_4 - start_4) * 100, 8))
print('comprehension_1: '.ljust(20), round((end_5 - start_5) * 100, 8))
print('comprehension_2: '.ljust(20), round((end_6 - start_6) * 100, 8))
  • 수행시간이 워낙 빠르다보니 부동소수점 e로 표현이 되는데 한눈에 파악하기 어려워 임의로 100을 곱하고 반올림하였다
    (참고: e앞에 부분이 가수부, e뒤에 부분이 지수부이며 밑수는 10이라는 의미
    14e2는 14 x 10^2이므로 1400, 123e-3이라면 123 x 10^-3 = 123 x 0.001 = 0.123이다)
 # input
abracadabra
5 k

# output
abrackdabra True
string_to_list: 0.00178814
string_format: 0.00100136
slice_join_1: 0.00040531
slice_join_2: 0.0002861
comprehension_1: 0.00193119
comprehension_2: 0.00107288

Find a string

예제 : ABCDCDC에서 CDC가 몇 번 나타나는가

ABCDCDC
CDC

2

import time

def count_substring(string, sub_string):
cnt = 0
sub_len = len(sub_string)
loop_len = len(string) - sub_len + 1

for i in range(loop_len):
if string[i:i + sub_len] == sub_string:
cnt += 1

return cnt

def list_comprehension(string, sub_string):
return sum([1 for i in range(len(string) - len(sub_string) + 1) if string[i:i + len(sub_string)] == sub_string])


def list_comprehension_2(string, sub_string):
s_len = len(string)
sub_len = len(sub_string)
return sum([1 for i in range(s_len - sub_len + 1) if string[i:i + sub_len] == sub_string])

if __name__ == '__main__':
string = input().strip()
sub_string = input().strip()

start_1 = time.time()
count = count_substring(string, sub_string)
end_1 = time.time()

start_2 = time.time()
count_1 = list_comprehension(string, sub_string)
end_2 = time.time()

start_3 = time.time()
count_2 = list_comprehension_2(string, sub_string)
end_3 = time.time()

print(count, list(map(lambda x: x == count, [count_1, count_2])))
print('count_substring: '.ljust(20), round((end_1 - start_1) * 100, 8))
print('list_1: '.ljust(20), round((end_2 - start_2) * 100, 8))
print('list_2: '.ljust(20), round((end_3 - start_3) * 100, 8))
  • list comprehension을 사용하는 것이 아주 미세하게 빠르다
 # input
ABCDCDC
CDC

# output
2 [True, True]
count_substring: 0.00219345
list_1: 0.00197887
list_2: 0.00190735

String Validators

아래 함수들은 각각 문자열이 해당 범위에 속하는지 확인한다
str.isalnum() : alphanumeric(a-z, A-Z and 0-9)
str.isalpha() : alphabetical (a-z and A-Z)
str.isdigit() : 숫자 (0-9)
str.islower() : 소문자 (a-z)
str.isupper() : 대문자 (A-Z)

예제 : 입력되는 문자열이 alphanumeric, alphabetical, digits, lowercase와 uppercase를 가지는지 True/False로 출력

qA2

True
True
True
True
True

if **name** == '**main**':
s = input()

'''깔끔한 코딩
for method in [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]:
print any(method(c) for c in s)
'''

print(any(c.isalnum() for c in s))
print(any(c.isalpha() for c in s))
print(any(c.isdigit() for c in s))
print(any(c.islower() for c in s))
print(any(c.isupper() for c in s))